package ooo.reindeer.logging;

import ooo.reindeer.commons.Property;
import ooo.reindeer.commons.utils.DateUtils;
import ooo.reindeer.commons.utils.StringUtil;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;

public class DefaultLogger implements ILogger {

    private static final LinkedBlockingQueue<LoggingMsg> msgQueue = new LinkedBlockingQueue<LoggingMsg>();
    String shortName;
    String name;
    Level level = conversion(Property.get("logger." + getName() + ".level", Property.get("logger.level", "INFO")));
    boolean async = Property.get("logger.async", false);

    public DefaultLogger(String name) {
        this.name = name;
        if (async) {
            Thread thread = LogWriter.thread;
        }
    }

    public DefaultLogger(Class clazz) {

        String loggerName = clazz.getName();
        if (loggerName.length() > 30) {
            StringBuffer stringBuffer = new StringBuffer(loggerName);
            StringBuffer classp = new StringBuffer();
            boolean push = true;
            boolean allwaysPush = false;
            for (int i = 0; i < stringBuffer.length(); i++) {
                if (stringBuffer.length() - i + classp.length() <= 30 && push) {
                    allwaysPush = true;
                }
                char temp = stringBuffer.charAt(i);
                if (temp == '.') {
                    push = true;
                    classp.append(temp);
                } else {
                    if (allwaysPush || push || stringBuffer.indexOf(".", i) == -1) {
                        classp.append(temp);
                        push = false;
                    }
                }
            }

            this.name = loggerName;
            this.shortName = classp.toString();
        } else {
            this.name = loggerName;
            this.shortName = this.name;
        }
        if (async) {
            Thread thread = LogWriter.thread;
        }

    }

    public DefaultLogger() {
        this.name = ROOT_LOGGER_NAME;
        this.shortName = this.name;
        if (async) {
            Thread thread = LogWriter.thread;
        }
    }

    private static Level conversion(String loggingLevel) {
        if (loggingLevel.equalsIgnoreCase("trace")) return Level.FINEST;
        if (loggingLevel.equalsIgnoreCase("debug")) return Level.CONFIG;
        if (loggingLevel.equalsIgnoreCase("info")) return Level.INFO;
        if (loggingLevel.equalsIgnoreCase("warn")) return Level.WARNING;
        if (loggingLevel.equalsIgnoreCase("error")) return Level.SEVERE;
        return Level.INFO;
    }

    private static String msgFormat(LoggingMsg msg) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer
                .append(DateUtils.getDateTime("yyyy-MM-dd HH:mm:ss.SSS", msg.getTimeStamp())).append(" [")
                .append(msg.getThreadName()).append("] [")
                .append(msg.getLevel()).append("] ")
                .append(msg.getLoggerName()).append(" - ");
        String text = msg.getMessage();
        if (msg.getArgArray() != null) {
            for (Object var : msg.getArgArray()) {

                text = StringUtil.replaceFirst(text, "{}", String.valueOf(var));

            }
        }
        stringBuffer.append(text);
        return stringBuffer.toString();
    }

    private static void write(LoggingMsg msg) {
        System.out.println(msgFormat(msg));
        if (msg.throwable != null) {
            msg.throwable.printStackTrace(System.out);
        }
    }

    @Override
    public void debug(String var1) {
        if (isDebugEnabled()) {
            LoggingMsg msg = new LoggingMsg("DEBUG", shortName, Thread.currentThread().getName(), var1, null, null);
            writer(msg);
        }
    }

    @Override
    public void debug(String var1, Object var2) {
        if (isDebugEnabled()) {
            LoggingMsg msg = new LoggingMsg("DEBUG", shortName, Thread.currentThread().getName(), var1, new Object[]{var2}, null);
            writer(msg);
        }
    }

    @Override
    public void debug(String var1, Object var2, Object var3) {
        if (isDebugEnabled()) {
            LoggingMsg msg = new LoggingMsg("DEBUG", shortName, Thread.currentThread().getName(), var1, new Object[]{var2, var3}, null);
            writer(msg);
        }

    }

    @Override
    public void debug(String var1, Object... var2) {
        if (isDebugEnabled()) {
            LoggingMsg msg = new LoggingMsg("DEBUG", shortName, Thread.currentThread().getName(), var1, var2, null);
            writer(msg);
        }
    }

    @Override
    public void debug(String var1, Throwable var2) {
        if (isDebugEnabled()) {
            LoggingMsg msg = new LoggingMsg("DEBUG", shortName, Thread.currentThread().getName(), var1, null, var2);
            writer(msg);
        }
    }

    @Override
    public void error(String var1) {
        if (isErrorEnabled()) {
            LoggingMsg msg = new LoggingMsg("ERROR", shortName, Thread.currentThread().getName(), var1, null, null);
            writer(msg);
        }
    }

    @Override
    public void error(String var1, Object var2) {
        if (isErrorEnabled()) {
            LoggingMsg msg = new LoggingMsg("ERROR", shortName, Thread.currentThread().getName(), var1, new Object[]{var2}, null);
            writer(msg);
        }
    }

    @Override
    public void error(String var1, Object var2, Object var3) {
        if (isErrorEnabled()) {
            LoggingMsg msg = new LoggingMsg("ERROR", shortName, Thread.currentThread().getName(), var1, new Object[]{var2, var3}, null);
            writer(msg);
        }
    }

    @Override
    public void error(String var1, Object... var2) {
        if (isErrorEnabled()) {
            LoggingMsg msg = new LoggingMsg("ERROR", shortName, Thread.currentThread().getName(), var1, var2, null);
            writer(msg);
        }
    }

    @Override
    public void error(String var1, Throwable var2) {
        if (isErrorEnabled()) {
            LoggingMsg msg = new LoggingMsg("ERROR", shortName, Thread.currentThread().getName(), var1, null, var2);
            writer(msg);
        }
    }

    @Override
    public ILogger getLogger(String logger) {
        return new DefaultLogger(logger);
    }

    @Override
    public ILogger getLogger(Class logger) {
        return new DefaultLogger(logger);
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void info(String var1) {
        if (isInfoEnabled()) {
            LoggingMsg msg = new LoggingMsg("INFO", shortName, Thread.currentThread().getName(), var1, null, null);
            writer(msg);
        }
    }

    @Override
    public void info(String var1, Object var2) {
        if (isInfoEnabled()) {
            LoggingMsg msg = new LoggingMsg("INFO", shortName, Thread.currentThread().getName(), var1, new Object[]{var2}, null);
            writer(msg);
        }
    }

    @Override
    public void info(String var1, Object var2, Object var3) {
        if (isInfoEnabled()) {
            LoggingMsg msg = new LoggingMsg("INFO", shortName, Thread.currentThread().getName(), var1, new Object[]{var2, var3}, null);
            writer(msg);
        }
    }

    @Override
    public void info(String var1, Object... var2) {
        if (isInfoEnabled()) {
            LoggingMsg msg = new LoggingMsg("INFO", shortName, Thread.currentThread().getName(), var1, var2, null);
            writer(msg);
        }
    }

    @Override
    public void info(String var1, Throwable var2) {
        if (isInfoEnabled()) {
            LoggingMsg msg = new LoggingMsg("INFO", shortName, Thread.currentThread().getName(), var1, null, var2);
            writer(msg);
        }
    }

    @Override
    public boolean isDebugEnabled() {
        return Level.CONFIG.intValue() >= level.intValue();
    }

    @Override
    public boolean isErrorEnabled() {
        return Level.SEVERE.intValue() >= level.intValue();
    }

    @Override
    public boolean isInfoEnabled() {
        return Level.INFO.intValue() >= level.intValue();
    }

    @Override
    public boolean isTraceEnabled() {
        return Level.FINEST.intValue() >= level.intValue();
    }

    @Override
    public boolean isWarnEnabled() {
        return Level.WARNING.intValue() >= level.intValue();
    }

    @Override
    public void trace(String var1) {
        if (isTraceEnabled()) {
            LoggingMsg msg = new LoggingMsg("TRACE", shortName, Thread.currentThread().getName(), var1, null, null);
            writer(msg);
        }
    }

    @Override
    public void trace(String var1, Object var2) {
        if (isTraceEnabled()) {
            LoggingMsg msg = new LoggingMsg("TRACE", shortName, Thread.currentThread().getName(), var1, new Object[]{var2}, null);
            writer(msg);
        }

    }

    @Override
    public void trace(String var1, Object var2, Object var3) {
        if (isTraceEnabled()) {
            LoggingMsg msg = new LoggingMsg("TRACE", shortName, Thread.currentThread().getName(), var1, new Object[]{var2, var3}, null);
            writer(msg);
        }
    }

    @Override
    public void trace(String var1, Object... var2) {
        if (isTraceEnabled()) {
            LoggingMsg msg = new LoggingMsg("TRACE", shortName, Thread.currentThread().getName(), var1, var2, null);
            writer(msg);
        }
    }

    @Override
    public void trace(String var1, Throwable var2) {
        if (isTraceEnabled()) {
            LoggingMsg msg = new LoggingMsg("TRACE", shortName, Thread.currentThread().getName(), var1, null, var2);
            writer(msg);
        }
    }

    @Override
    public void warn(String var1) {
        if (isWarnEnabled()) {
            LoggingMsg msg = new LoggingMsg("WARN", shortName, Thread.currentThread().getName(), var1, null, null);
            writer(msg);
        }
    }

    @Override
    public void warn(String var1, Object var2) {
        if (isWarnEnabled()) {
            LoggingMsg msg = new LoggingMsg("WARN", shortName, Thread.currentThread().getName(), var1, new Object[]{var2}, null);
            writer(msg);
        }
    }

    @Override
    public void warn(String var1, Object... var2) {
        if (isWarnEnabled()) {
            LoggingMsg msg = new LoggingMsg("WARN", shortName, Thread.currentThread().getName(), var1, var2, null);
            writer(msg);
        }
    }

    @Override
    public void warn(String var1, Object var2, Object var3) {
        if (isWarnEnabled()) {
            LoggingMsg msg = new LoggingMsg("WARN", shortName, Thread.currentThread().getName(), var1, new Object[]{var2, var3}, null);
            writer(msg);
        }
    }

    @Override
    public void warn(String var1, Throwable var2) {
        if (isWarnEnabled()) {
            LoggingMsg msg = new LoggingMsg("WARN", shortName, Thread.currentThread().getName(), var1, null, var2);
            writer(msg);
        }
    }

    private void writer(LoggingMsg msg) {

        if (async) {
            msgQueue.add(msg);
        } else {
            write(msg);
        }
    }

    static class LogWriter {
        private static final Thread thread = new Thread(new Runnable() {

            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        LoggingMsg msg = msgQueue.take();
                        write(msg);
                    } catch (Exception e) {
                    }
                }
            }

        });

        static {
            thread.setName("LogWriter");
            thread.setDaemon(true);
            thread.start();
        }
    }
}
